﻿/* PCi RAGE Launcher, a simple configuration Tool for RAGE Game

Copyright © 2011 - LEGRAND David - PC INpact.com
Mail : david@pcinpact.com

Google Code Project : http://code.google.com/p/pci-rage-launcher/
Forum : http://forum.pcinpact.com/topic/159874-pci-tool-pci-rage-launcher/

This file is part of PCi RAGE Launcher.

PCi RAGE Launcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PCi RAGE Launcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PCi RAGE Launcher.  If not, see <http://www.gnu.org/licenses/>.

You're not allowed to use PCi RAGE Launcher name or logo without permission

*/

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

namespace PCi_RAGE_Launcher
{
    public partial class Form1 : Form
    {
        // On définit les variables utiles
        private string exe = "Rage.exe";

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // On affiche le nom de l'application ainsi que son numéro de version
            this.Text = Application.ProductName + " " + Application.ProductVersion;

            // On récupère l'état du formulaire
            Load_form_values();

            // Si aucun chemin n'est enregistré pour l'exécutable
            if (path.Default.app_path == "")
            {
                // Lecture depuis la base de registre
                string path_end = @"\SteamApps\common\rage\Rage.exe";
                string steam_path_reg = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Valve\Steam", "SteamPath", null).ToString();

                // Si l'on a récupéré une variable
                if (steam_path_reg != null)
                {
                    // On créé le chemin complet
                    string temp_file = steam_path_reg + path_end;
                    
                    // Si le fichier existe bel et bien, on place la variable dans le champ
                    if (System.IO.File.Exists(temp_file)) app_path.Text = temp_file.Replace(@"/", @"\");
                }
            }
            // Si un chemin est déjà enregistré, on l'utilise
            else app_path.Text = path.Default.app_path;

            // Si une langue est enregistrée, on l'utilise
            // 69 est la valeur par défaut du champ, elle n'est donc valable que s'il n'a jamais été initialisé
            if (lang.Default.locale != 69)
            {
                cb_lang.SelectedIndex = lang.Default.locale;
            }
            // Sinon, on utilise la langue française si le système est FR, anglaise dans les autres cas
            else cb_lang.SelectedIndex = (Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName == "fr") ? 1 : 0;

            // On détermine l'état des boutons Load / Save / Go
            Get_buttons_states();
        }

        // Quand on clique sur le lien du site, on envoie l'utilisateur sur PC INpact
        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start("http://forum.pcinpact.com/topic/159874-pci-tool-pci-rage-launcher");
        }

        // Quand on clique sur le lien du projet, envoie l'utilisateur sur Google Code 
        private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start("https://code.google.com/p/pci-rage-launcher/");
        }

        // Quand on demande un reset
        private void reset_button_Click(object sender, EventArgs e)
        {
            // On réinitialise les valeurs, puis on les affiche
            Reset_Parameters();
            Load_form_values();

            // On active le mode par défaut et on met à jour les boutons
            data.Default.def_mode = true;
            Get_buttons_states();
        }

        // Lorsque l'on clique sur le bouton sauvegarder
        private void save_button_Click(object sender, EventArgs e)
        {
            // On lance la fonction de backup
            Save_form_values();

            // On désactive le mode par défaut et on met à jour les boutons
            data.Default.def_mode = false;
            Get_buttons_states();
        }

        // Lorsque l'on clique sur le bouton charger
        private void load_button_Click(object sender, EventArgs e)
        {
            // On affiche les dernières valeurs enregistrées
            Load_form_values();
        }

        // Quand on appuie sur le bouton Go
        private void go_button_Click(object sender, EventArgs e)
        {

            // Si le champ du path n'est pas vide, on passe à la suite
            if (app_path.Text != "")
            {
                // On récupère les arguments depuis la fenêtre
                string app_args = Args_fill();

                // On écrit le fichier relatif aux textures
                // On effectue le tout dans un try /catch
                try { Write_texture_file("rageconfig.cfg", chk_simple_mode.Checked); }
                catch (Exception ex) { Error_message(ex); }

                // On définit si l'on est dans un cas Steam ou non 
                bool is_steam = Tools.Is_steam(app_path.Text);

                // On créé le processus
                Process game = new Process();

                // Si le jeu est lancé via Steam on utilise les paramètre de Steam
                if (is_steam)
                {
                    game.StartInfo.FileName = app_path.Text.Replace(@"\SteamApps\common\rage\" + exe, "") + @"\Steam.exe";
                    game.StartInfo.Arguments = "-applaunch 9200 " + app_args;
                }

                // Sinon on utilise les valeurs de base
                else
                {
                    game.StartInfo.FileName = app_path.Text;
                    game.StartInfo.Arguments = app_args;
                }

                // On place le tout dans un try catch pour éviter les erreurs
                try
                {
                    // On lance le jeu, et on attend la fin du processus
                    game.Start();

                    // Si le SAFE Mode  été lancé, on le désactive pour l'utilisation suivante
                    if (chk_safe_mode.Checked) chk_safe_mode.Checked = false;
                }
                catch (Exception ex) { Error_message(ex); }
            }
            // Si le champ est vide, on incite l'utilisateur à le remplir
            else Get_path();
        }

        // Lorsque la case du mode simple est cochée
        private void chk_simple_mode_CheckedChanged(object sender, EventArgs e)
        {
            // On change l'état des contrôles à l'inverse de l'état de la case
            groupBox2.Enabled = !chk_simple_mode.Checked;
        }

        // Quand on clique sur le champ dédié au chemin du jeu
        private void app_path_Click(object sender, EventArgs e)
        {
            // On va chercher l'exécutable
            Get_path();
        }

        // La fonction qui permet de récupérer le chemin de l'exécutable
        private void Get_path()
        {
            // Si l'utilisateur valide le formulaire ouvert
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                // Si le fichier renvoyé existe bel et bien
                if (System.IO.File.Exists(openFileDialog1.FileName) && openFileDialog1.FileName.Contains(exe))
                {
                    // On remplit le champ avec le chemin validé
                    app_path.Text = openFileDialog1.FileName;
                    
                    // On l'enregistre dans le fichier de paramètres
                    path.Default.app_path = openFileDialog1.FileName;
                    path.Default.Save();

                    // On check l'état des boutons, qui dépend du statut de l'app_path
                    Get_buttons_states();
                }
            }
        }

        // La fonction qui réinitialise les paramètres les valeurs par défaut
        private void Reset_Parameters()
        {
            // On remet à zéro les paramètres
            data.Default.Reset();

            // On gère le cas du Max PPF qui dépend du nombre de coeurs détectés
            if (Environment.ProcessorCount <= 2) data.Default.max_ppf = 0;
            else if (Environment.ProcessorCount > 2 && Environment.ProcessorCount <= 4) data.Default.max_ppf = 1;
            else if (Environment.ProcessorCount > 4 && Environment.ProcessorCount <= 8) data.Default.max_ppf = 2;
            else if (Environment.ProcessorCount > 8 && Environment.ProcessorCount <= 16) data.Default.max_ppf = 3;
            else data.Default.max_ppf = 4;
        }

        // La fonction qui détermine l'état du bouton Go / Par défaut
        private void Get_buttons_states()
        {
            // Si le fichier indiqué dans App_path existe, on permet le lancement 
            go_button.Enabled = (System.IO.File.Exists(app_path.Text)) ? true : false;

            load_button.Enabled = (!data.Default.def_mode);
        }

        // La fonction qui sauvegarde les données du formulaire
        private void Save_form_values()
        {
            data.Default.fov = num_FOV.Value;
            data.Default.m_smooth = num_m_smooth.Value;
            data.Default.console = chk_console.Checked;
            data.Default.intro_video = chk_video.Checked;
            data.Default.fullscreen = chk_fs.Checked;
            data.Default.simple_mode = chk_simple_mode.Checked;

            data.Default.player_shadow = chk_shadow.Checked;
            data.Default.image_compression = chk_img_compress.Checked;
            data.Default.aa = cb_aa.SelectedIndex;
            data.Default.af = cb_af.SelectedIndex;
            data.Default.textures = cb_textures.SelectedIndex;
            data.Default.max_ppf = cb_PPF.SelectedIndex;
            data.Default.num_threads = num_threads.Value;

            // On sauvegarde le fichier de config
            data.Default.Save();

            // On informe l'utilisateur
            MessageBox.Show(messages.saved_msg, messages.saved_msg_title, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        // La fonction qui récupère les données du formulaire depuis le fichier de paramètres
        private void Load_form_values()
        {
            num_FOV.Value = data.Default.fov;
            num_m_smooth.Value = data.Default.m_smooth;
            chk_console.Checked = data.Default.console;
            chk_video.Checked = data.Default.intro_video;
            chk_fs.Checked = data.Default.fullscreen;
            chk_simple_mode.Checked = data.Default.simple_mode;

            chk_shadow.Checked = data.Default.player_shadow;
            chk_img_compress.Checked = data.Default.image_compression;
            cb_aa.SelectedIndex = data.Default.aa;
            cb_af.SelectedIndex = data.Default.af;
            cb_textures.SelectedIndex = data.Default.textures;
            cb_PPF.SelectedIndex = data.Default.max_ppf;
            num_threads.Value = data.Default.num_threads;
        }

        // La fonction qui écrit le fichier relatif aux textures
        private void Write_texture_file(string CFG_file, bool simple_mode)
        {
            // On récupère le chemin du répertoire "base"
            string base_path = app_path.Text.Replace(exe, @"\base");

            // Si les textures demandées ne sont pas la valeur standard
            if (cb_textures.SelectedIndex != 0 && simple_mode != true)
            {
                // On calcule la valeur à utiliser
                int texture_value = 4096;
                switch (cb_textures.SelectedIndex)
                {
                    case 1:
                        texture_value *= 1;
                        break;

                    case 2:
                        texture_value *= 2;
                        break;

                    case 3:
                        texture_value *= 4;
                        break;
                }

                // On remplit un tableau de string avec les valeurs
                string[] lines = {  "vt_pageimagesizeuniquediffuseonly2 " + texture_value.ToString(),
                                    "vt_pageimagesizeuniquediffuseonly " + texture_value.ToString(),
                                    "vt_pageimagesizeunique " + texture_value.ToString(),
                                    "vt_pageimagesizevmtr " + texture_value.ToString(),
                                    "vt_restart "};

                // On écrit le fichier de sortie
                System.IO.File.WriteAllLines(base_path + @"\" + CFG_file, lines);
            }
            // Si l'utlisateur a demandé les textures standard, on efface le fichier
            else if (System.IO.File.Exists(base_path + @"\" + CFG_file)) System.IO.File.Delete(base_path + @"\" + CFG_file);
        }

        // La fonction qui renvoie la liste des arguments
        private string Args_fill()
        {
            // On initialise la variable de sortie
            string app_args = "";

            // On récupère les différentes valeurs
            // On rallonge la ligne d'argument en fonction de celles-ci

            app_args += "+set com_allowconsole ";
            app_args += (chk_console.Checked == true) ? "1" : "0";

            app_args += " +com_skipIntroVideo ";
            app_args += (chk_video.Checked == true) ? "0" : "1";

            app_args += " +r_fullscreen ";
            app_args += (chk_fs.Checked == true) ? "1" : "0";

            app_args += " +com_safemode ";
            app_args += (chk_safe_mode.Checked == true) ? "1" : "0";

            app_args += " +m_smooth " + num_m_smooth.Value;

            app_args += " +g_fov " + num_FOV.Value;

            // On ne traite certaines variables que si l'on est pas en mode simple
            if (!chk_simple_mode.Checked)
            {
                app_args += " +image_usecompression ";
                app_args += (chk_img_compress.Checked == true) ? "1" : "0";

                app_args += " +g_showplayershadow ";
                app_args += (chk_shadow.Checked == true) ? "1" : "0";

                app_args += " +image_anisotropy " + cb_af.SelectedItem.ToString().Substring(0, 1);
                app_args += " +vt_maxAniso " + cb_af.SelectedItem.ToString().Substring(0, 1);

                app_args += " +vt_maxPPF " + cb_PPF.SelectedItem.ToString();

                app_args += " +r_multiSamples " + cb_aa.SelectedItem.ToString().Substring(0, 1);

                app_args += " +jobs_numThreads " + num_threads.Value;
            }

            // Zone de test
            // MessageBox.Show(app_args);

            // On renvoie le résultat
            return app_args;
        }

        // La fonction qui affiche le message d'erreur
        private static void Error_message(Exception ex)
        {
            MessageBox.Show(messages.error_msg, messages.error_msg_title, MessageBoxButtons.OK, MessageBoxIcon.Error);
            System.IO.File.WriteAllText(Program.Err_file, ex.ToString());
        }

        // Lorsque l'on demande un changement de la langue
        private void cb_lang_SelectedIndexChanged(object sender, EventArgs e)
        {
            // On fonction de l'index, on renvoie le fichier de langue adapté
            switch (cb_lang.SelectedIndex)
            {
                case 0:
                    ChangeLanguage("en");
                    break;

                case 1:
                    ChangeLanguage("fr-FR");
                    break;
            }

            // On sauvegarde l'information
            lang.Default.locale = cb_lang.SelectedIndex;
            lang.Default.Save();
        }

        // La fonction qui met à jour les éléments du formulaire en fonction de la langue
        private void ChangeLanguage(string lang)
        {
            // On met à jour les éléments du formulaire
            foreach (Control c in this.Controls)
            {
                ComponentResourceManager resources = new ComponentResourceManager(typeof(Form1));
                resources.ApplyResources(c, c.Name, new CultureInfo(lang));
            }

            // On met à jour les élements contenus dans les différentes Groupbox
            foreach (Control c in this.groupBox1.Controls)
            {
                ComponentResourceManager resources = new ComponentResourceManager(typeof(Form1));
                resources.ApplyResources(c, c.Name, new CultureInfo(lang));
            }

            foreach (Control c in this.groupBox2.Controls)
            {
                ComponentResourceManager resources = new ComponentResourceManager(typeof(Form1));
                resources.ApplyResources(c, c.Name, new CultureInfo(lang));
            }

            // On met à jour le RessourceManger des messages
            messages.Culture = new CultureInfo(lang);
        }
    }
}
